package com.mall.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mall.common.model.GlobalResponse;
import com.mall.dao.OrderItemMapper;
import com.mall.dao.OrderMapper;
import com.mall.dao.ProductMapper;
import com.mall.dao.ShippingMapper;
import com.mall.enums.GlobalResponseEnum;
import com.mall.enums.OrderStatusEnum;
import com.mall.enums.PaymentTypeEnum;
import com.mall.enums.ProductStatusEnum;
import com.mall.pojo.*;
import com.mall.service.ICartService;
import com.mall.service.IOrderService;
import com.mall.vo.OrderItemVO;
import com.mall.vo.OrderVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Classname OrderServiceImpl
 * @Description
 * @Date 2022/7/31 19:20
 * @Created by TaoVh
 */
@Service
public class OrderServiceImpl implements IOrderService {

    @Autowired
    private ShippingMapper shippingMapper;

    @Autowired
    private ICartService cartService;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderItemMapper orderItemMapper;

    @Override
    @Transactional
    public GlobalResponse<OrderVO> create(Integer uid, Integer shippingId) {
        /*收货地址校验(总之要查出来的)*/
        Shipping shipping = shippingMapper.selectByUidAndShippingId(uid, shippingId);
        if (shipping == null) return GlobalResponse.error(GlobalResponseEnum.SHIPPING_NOT_EXIST);
        /*获取购物车，校验（是否有商品、库存）*/
        List<Cart> cartList = cartService.listForCart(uid)
                .stream()
                .filter(Cart::getProductSelected)
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(cartList)) {
            return GlobalResponse.error(GlobalResponseEnum.CART_SELECTED_IS_EMPTY);
        }
        /*获取cartList里面的productIds*/
        Set<Integer> idSet = cartList.stream()
                .map(Cart::getProductId)
                .collect(Collectors.toSet());
        List<Product> productList = productMapper.selectByProductIdSet(idSet);
        Map<Integer, Product> map = productList.stream()
                .collect(Collectors.toMap(Product::getId, product -> product));

        List<OrderItem> orderItemList = new ArrayList<>();
        Long orderNo = generateOrderNo();
        for (Cart cart : cartList) {
            Product product = map.get(cart.getProductId());
            if (product == null) {
                return GlobalResponse.error(GlobalResponseEnum.PRODUCT_NOT_EXIST,
                        "商品不存在. productId = " + cart.getProductId());
            }
            /*商品的上下架状态*/
            if (!ProductStatusEnum.ON_SALE.getCode().equals(product.getStatus())) {
                return GlobalResponse.error(GlobalResponseEnum.PRODUCT_OFF_SALE_OR_DELETE,
                        "商品不是在售状态. " + product.getName());
            }
            /*库存是否充足*/
            if (product.getStock() < cart.getQuantity()) {
                return GlobalResponse.error(GlobalResponseEnum.PRODUCT_STOCK_ERROR,
                        "库存不正确." + product.getName());
            }
            OrderItem orderItem = buildOrderItem(uid, orderNo, product, cart.getQuantity());
            orderItemList.add(orderItem);

            /*减库存*/
            product.setStock(product.getStock() - cart.getQuantity());
            int row = productMapper.updateByPrimaryKeySelective(product);
            if (row <= 0) return GlobalResponse.error(GlobalResponseEnum.ERROR);
        }
        /*计算总价格，只计算选中商品*/
        Order order = buildOrder(uid, orderNo, shippingId, orderItemList);
        /*生成订单，入库：order&order_item，事务保证一致性*/
        int rowForOrder = orderMapper.insertSelective(order);
        if (rowForOrder <= 0) {
            return GlobalResponse.error(GlobalResponseEnum.ERROR);
        }
        int rowForOrderItem = orderItemMapper.batchInsert(orderItemList);
        if (rowForOrderItem <= 0) {
            return GlobalResponse.error(GlobalResponseEnum.ERROR);
        }
        /*更新购物车（选中的商品删掉）*/
        for (Cart cart : cartList) {
            cartService.delete(uid, cart.getProductId());
        }
        /*构造orderVO*/
        OrderVO orderVO = buildOrderVO(order, orderItemList, shipping);
        return GlobalResponse.successByData(orderVO);
    }

    @Override
    public GlobalResponse<PageInfo> list(Integer uid, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Order> orderList = orderMapper.selectByUid(uid);
        Set<Long> orderNoSet = orderList.stream()
                .map(Order::getOrderNo)
                .collect(Collectors.toSet());
        List<OrderItem> orderItemList = orderItemMapper.selectByOrderNoSet(orderNoSet);

        Map<Long, List<OrderItem>> orderItemMap = orderItemList.stream()
                .collect(Collectors.groupingBy(OrderItem::getOrderNo));

        Set<Integer> shippingIdSet = orderList.stream()
                .map(Order::getShippingId)
                .collect(Collectors.toSet());

        List<Shipping> shippingList = shippingMapper.selectByIdSet(shippingIdSet);
        Map<Integer, Shipping> shippingMap = shippingList.stream()
                .collect(Collectors.toMap(Shipping::getId, shipping -> shipping));

        List<OrderVO> orderVOList = new ArrayList<>();

        for (Order order : orderList) {
            OrderVO orderVO = buildOrderVO(order,
                    orderItemMap.get(order.getOrderNo()),
                    shippingMap.get(order.getShippingId()));
            orderVOList.add(orderVO);
        }
        PageInfo pageInfo = new PageInfo(orderVOList);
        return GlobalResponse.successByData(pageInfo);
    }

    @Override
    public GlobalResponse<OrderVO> detail(Integer uid, Long orderNo) {
        Order order = orderMapper.selectByOrderNoAndUid(uid, orderNo);
        if (order == null) return GlobalResponse.error(GlobalResponseEnum.ORDER_NOT_EXIST);
        List<OrderItem> orderItemList = orderItemMapper.selectByOrderNo(order.getOrderNo());

        Shipping shipping = shippingMapper.selectByPrimaryKey(order.getShippingId());

        List<OrderItemVO> orderItemVOList = new ArrayList<>();
        for (OrderItem orderItem : orderItemList) {
            OrderItemVO orderItemVO = new OrderItemVO();
            BeanUtils.copyProperties(orderItem, orderItemVO);
            orderItemVOList.add(orderItemVO);
        }
        OrderVO orderVO = buildOrderVO(order, orderItemList, shipping);
        return GlobalResponse.successByData(orderVO);
    }

    @Override
    @Transactional
    public GlobalResponse unOrder(Integer uid,Long orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);

        if (order==null) {
            return GlobalResponse.error(GlobalResponseEnum.ORDER_NOT_EXIST);
        }
        if (uid.equals(order.getUserId())){
            return GlobalResponse.error(GlobalResponseEnum.ORDER_NOT_EXIST);
        }
        if (!OrderStatusEnum.NO_PAY.getCode().equals(order.getStatus())){
            return GlobalResponse.error(GlobalResponseEnum.UNDO_PAID_ORDER_ERROR);
        }
        /*保证同时删除mall_order&mall_order_item中的数据，使用事务*/
        int rowForOrder = orderMapper.deleteByOrderNo(orderNo);
        if (rowForOrder<=0) return GlobalResponse.error(GlobalResponseEnum.ERROR);

        int rowForOrderItem = orderItemMapper.deleteByOrderNo(orderNo);
        if (rowForOrderItem<=0)return GlobalResponse.error(GlobalResponseEnum.ERROR);

        return new GlobalResponse(0);
    }

    @Override
    public void paid(long orderNo) {
        Order order = orderMapper.selectByOrderNo(orderNo);
        if (order==null) {
            throw new RuntimeException(GlobalResponseEnum.ORDER_NOT_EXIST.getDescription()+"订单ID："+orderNo);
        }
        /*只有未付款订单可以变成已付款*/
        if (!OrderStatusEnum.NO_PAY.getCode().equals(order.getStatus())){
            throw new RuntimeException(GlobalResponseEnum.ORDER_STATUS_ERROR.getDescription()+"订单ID："+orderNo);
        }
        order.setStatus(OrderStatusEnum.PAID.getCode());
        order.setPaymentTime(new Date());
        int row = orderMapper.updateByPrimaryKeySelective(order);
        if (row<=0) {
            throw new RuntimeException("将订单更新为已支付状态失败"+"订单ID："+orderNo);
        }
    }

    private OrderVO buildOrderVO(Order order, List<OrderItem> orderItemList, Shipping shipping) {
        OrderVO orderVO = new OrderVO();
        BeanUtils.copyProperties(order, orderVO);

        List<OrderItemVO> orderItemVOList = orderItemList.stream().map(orderItem -> {
            OrderItemVO orderItemVO = new OrderItemVO();
            BeanUtils.copyProperties(orderItem, orderItemVO);
            return orderItemVO;
        }).collect(Collectors.toList());
        orderVO.setOrderItemVOList(orderItemVOList);
        if(shipping!=null){
            orderVO.setShippingId(shipping.getId());
            orderVO.setShippingVO(shipping);
        }
        return orderVO;
    }

    private Order buildOrder(Integer uid,
                             Long orderNo,
                             Integer shippingId,
                             List<OrderItem> orderItemList) {
        BigDecimal payment = orderItemList.stream()
                .map(OrderItem::getTotalPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        Order order = new Order();
        order.setOrderNo(orderNo);
        order.setUserId(uid);
        order.setShippingId(shippingId);
        order.setPayment(payment);
        order.setPaymentType(PaymentTypeEnum.PAY_ONLINE.getCode());
        order.setPostage(0);
        order.setStatus(OrderStatusEnum.NO_PAY.getCode());
        return order;
    }

    /*TODO 企业级：分布式唯一ID*/
    private Long generateOrderNo() {
        long l = RandomUtil.randomLong();
        return l < 0 ? -l : l;
    }

    private OrderItem buildOrderItem(Integer uid, Long orderNo, Product product, Integer quantity) {
        OrderItem item = new OrderItem();
        item.setUserId(uid);
        item.setOrderNo(orderNo);
        item.setProductId(product.getId());
        item.setProductName(product.getName());
        item.setProductImage(product.getMainImage());
        item.setCurrentUnitPrice(product.getPrice());
        item.setQuantity(quantity);
        item.setTotalPrice(product.getPrice().multiply(BigDecimal.valueOf(quantity)));
        return item;
    }
}
